home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / NeoIntroAlone3.0 folder / Standalone / NeoBench / Source / CStandApp.cp < prev   
Encoding:
Text File  |  1994-09-28  |  14.2 KB  |  588 lines  |  [TEXT/KAHL]

  1. /****
  2.  * CStandApp.c
  3.  *
  4.  *    Methods for a standalone Stand application class.
  5.  *
  6.  *    Copyright © 1992 NeoLogic Systems.    All rights reserved.
  7.  *
  8.  ****/
  9.  
  10. #include "NeoTypes.h"
  11. #include CNeoDatabaseNativeH
  12.  
  13. #include <Timer.h>
  14. #include <time.h>
  15. #include <stdlib.h>
  16. #include <Traps.h>
  17. #include <StandardFile.h>
  18. #ifdef THINK_CPLUS
  19. #include <console.h>
  20. #endif
  21. #if __MWERKS__
  22. #include <SIOUX.h>
  23. #endif
  24. #include <new.h>
  25.  
  26. #include "CStandApp.h"
  27. #include CNeoMetaClassH
  28. #include CNeoIndexIteratorH
  29. #include "CFiller.h"
  30. #include CNeoPersistH
  31.  
  32. #ifndef NeoInherited
  33. #define NeoInherited    CNeoAppAlone
  34. #endif
  35.  
  36. #define k30MicroMinutes        -(1800000000L)
  37.  
  38. long gLoopOverhead;            // Timer Manager Overhead
  39.  
  40. static long default_vals[5] = {25000, 25000, 25000, 25000, 25000};
  41. #ifdef qNeoThreads
  42. static long default_threads[5] = {1, 2, 2, 2, 1};
  43. #endif
  44.  
  45. static Str255 PhaseName[] = {    "         Insert",
  46.                                 "Locate Randomly",
  47.                                 "Locate Serially",
  48.                                 "         Change",
  49.                                 "         Delete"};
  50. static Str255 ColNames[] = { "\pTotal", "\pSo Far", "\pPer Record", "\pTotal"};
  51.                             
  52. void main(void)
  53. {
  54.     CStandApp    app;                    
  55.  
  56.     app.run();
  57.     app.exit();
  58. }
  59.  
  60. void CStandApp::NewHandler(void)
  61. {
  62.     gNeoApp->purge(1);
  63. }
  64.  
  65. #pragma segment NeoCreate
  66. CStandApp::CStandApp(void)
  67. {
  68.     long        index;
  69.     long        delay        = 0;
  70.     TMTask        timer;
  71.     SFReply        macSFReply;
  72.  
  73.     set_new_handler(NewHandler);
  74.  
  75. #ifdef qNeoThreads
  76.     fThreadCount = 0;
  77.     for (index = 0; index < kMaxThreads; index++)
  78.         fThreadInfo[index].thread = nil;
  79. #endif
  80.  
  81.     fDatabase = new CNeoDatabaseAlone(kNeoStandSig, kNeoStandFileType);
  82.     gNeoDatabase = fDatabase;
  83.     fIterator = nil;
  84.  
  85.     ChooseFile(&macSFReply);
  86.     fDatabase->SFSpecify(&macSFReply);
  87.     fDatabase->create();
  88.     fDatabase->open(fsRdWrPerm);
  89.  
  90.     //---------------------------------------------------
  91.     // Get the numbers from the Dialog box,    and update
  92.     // the fields with the values of the numbers the
  93.     // user has typed in.    Also,    if the user has typed
  94.     // in out of range numbers,    correct them.
  95.     //---------------------------------------------------
  96.     getTargetTotals();
  97.     
  98.     //---------------------------------------------------
  99.     //    I am not sure at this point if you will want to
  100.     //    initialize the fields in the fPhaseInfo records
  101.     //    other than the totals which come from the users
  102.     //    text boxes.    If the other fields need
  103.     //    initializing,    we do it here.            
  104.     //---------------------------------------------------
  105.     for (index = kMinPhase;    index <= kMaxPhase; index++) {
  106.         fPhaseInfo[index].dirty = FALSE;
  107. #ifdef __MWERKS__
  108.         fPhaseInfo[index].finished = FALSE;
  109. #endif
  110.         fPhaseInfo[index].committed = 0;
  111.         fPhaseInfo[index].done = 0;
  112.         fPhaseInfo[index].delta = 0;
  113.         fPhaseInfo[index].soFar = 0;
  114. #ifdef qNeoThreads
  115.         fPhaseInfo[index].threadCount = default_threads[index];
  116. #endif
  117.     }
  118.  
  119.     if (fPhaseInfo[kInsert].delta < fPhaseInfo[kInsert].target)
  120.         fPhase = kMinPhase;
  121.     else
  122.         fPhase = kRandomly;
  123.  
  124.     fDirty = FALSE;
  125.     fState = kStart;
  126.     fRefresh = TRUE;
  127.  
  128.     // Just to make sure that we get more random results.
  129.     srand((unsigned int)clock());
  130.  
  131.     // measure Time Manager overhead
  132.     timer.tmAddr        = NULL;
  133.     timer.tmCount        = 0;
  134.     timer.tmWakeUp        = 0;
  135.     timer.tmReserved    = 0;
  136.     
  137.     for (index = 0; index < 100; index++) {
  138.         InsTime((QElemPtr)&timer);
  139.         PrimeTime((QElemPtr)&timer, k30MicroMinutes);
  140.         RmvTime((QElemPtr)&timer);
  141.         
  142.         if (timer.tmCount > 0)
  143.             // milliseconds
  144.             delay += -(k30MicroMinutes + timer.tmCount * 1000);
  145.         else
  146.             // negated microseconds
  147.             delay += -(k30MicroMinutes - timer.tmCount);
  148.     }
  149.     
  150.     // compute average overhead
  151.     gLoopOverhead = delay / 100;
  152.  
  153. #ifdef THINK_CPLUS
  154.     console_options.nrows = 5;
  155.     console_options.ncols = 90;
  156.     NeoBlockMove("\pNeoAccess", console_options.title, 10);
  157.     cshow(stdout);
  158.     cgotoxy(1, 1, stdout);
  159. #endif
  160. #if __MWERKS__
  161.     SetSIOUXBufferMode(SIOUXNoBuffering);
  162. #endif
  163.  
  164.     // Add CFiller class to the metaclass table
  165.     new CNeoMetaClass(kFillerID, kNeoPersistID, kFillerName, CFiller::New);
  166.  
  167.     // Bound the default size of the NeoAccess object cache to be 3/4 of free memory
  168.     CNeoPersist::FCacheSize = ((FreeMem() / 4) * 3);
  169.  
  170.     setState(kStart);
  171. }
  172.  
  173. #pragma segment NeoDestroy
  174. CStandApp::~CStandApp(void)
  175. {
  176. #ifdef qNeoThreads
  177.     killThreads();
  178. #endif
  179.  
  180.     if (gNeoDatabase) {
  181.         gNeoDatabase->close();
  182.         gNeoDatabase = nil;
  183.     }
  184. }
  185.  
  186. void CStandApp::setPhase(const short aPhase)
  187. {
  188. #ifdef qNeoThreads
  189.     short    index;
  190.     short    count;
  191.  
  192.     if (aPhase >= kMinPhase &&
  193.         aPhase <= kMaxPhase)
  194.         count = fPhaseInfo[aPhase].threadCount;
  195.     else {
  196.         if (fIterator) {
  197.             delete fIterator;
  198.             fIterator = nil;
  199.         }
  200.         count = 0;
  201.     }
  202.  
  203.     for (index = 0; index < count; index++) {
  204.         fThreadInfo[index].phase = aPhase;
  205.         fThreadInfo[index].state = kAlive;
  206.         if (index >= fThreadCount) {
  207.             fThreadInfo[index].thread = new CBenchThread(&fThreadInfo[index]);
  208.             fThreadCount++;
  209.             fThreadInfo[index].thread->resume();
  210.         }
  211.     }
  212.  
  213.     for (index = fThreadCount; index > count; index--)
  214.         fThreadInfo[index].state = kDie;
  215. #endif
  216.  
  217.     fPhase = aPhase;
  218. }
  219.  
  220. void CStandApp::setState(const Boolean aState)
  221. {
  222.     short    index;
  223.     short    phase;
  224.  
  225.     if (aState == kStop) {
  226. #ifdef qNeoThreads
  227.         killThreads();
  228. #endif
  229.         phase = kNoPhase;
  230.     }
  231.     else {
  232.         for (index = kMinPhase;  index <= kMaxPhase; index++) {
  233. #if __MWERKS__
  234.             fPhaseInfo[index].finished = FALSE;
  235. #endif
  236.             fPhaseInfo[index].done = 0;
  237.             fPhaseInfo[index].delta = 0;
  238.             fPhaseInfo[index].committed = 0;
  239.             fPhaseInfo[index].soFar = 0;
  240.         }
  241.  
  242.         if (fPhaseInfo[kInsert].delta < fPhaseInfo[kInsert].target)
  243.             phase = kMinPhase;
  244.         else
  245.             phase = kRandomly;
  246.     }
  247.     fState = aState;
  248.  
  249.     setPhase(phase);
  250. }
  251.  
  252. /******************************************************************************
  253.  spendTime
  254.  ******************************************************************************/
  255. void CStandApp::doChores(void)
  256. {
  257.     short            index;
  258.     long            count;
  259.     long            loops        = 0;
  260.     CNeoDatabase *    database    = getDatabase();
  261.     char            string[20];
  262.  
  263.     NeoUsed(loops);
  264.  
  265.     if (fState == kStart) {
  266. #ifndef qNeoThreads
  267.         TMTask            timer;
  268.  
  269.         doSomeWork(fPhase, &timer);
  270. #endif
  271.  
  272.         for (index = kMinPhase; index <= kMaxPhase; index++) {
  273. #if __MWERKS__
  274.             if (fPhaseInfo[index].finished)
  275. #endif
  276.             if (fPhaseInfo[index].dirty) {
  277. #ifdef THINK_CPLUS
  278.                 cgotoxy(1, index +1, stdout);
  279.                 ccleol(stdout);
  280. #endif
  281.                 printf("%s -> ", PhaseName[index]);
  282.                 printf("Total = %6ld, ", (fPhaseInfo[index].delta + fPhaseInfo[index].done));
  283.                 getTime(fPhaseInfo[index].soFar / (fPhaseInfo[index].done ? fPhaseInfo[index].done : 1), string);
  284.                 count = (long)(((double)fPhaseInfo[index].committed / (double)(fPhaseInfo[index].soFar ? fPhaseInfo[index].soFar : 1)) * 1000000);
  285.                 printf("Obj./Sec. = %6ld, ", count);
  286.                 getTime(fPhaseInfo[index].soFar, string);
  287.                 printf("Total Time = %s", string);
  288.                 fPhaseInfo[index].dirty = FALSE;
  289. #if __MWERKS__
  290.                 printf("\n");
  291.                 fPhaseInfo[index].finished = FALSE;
  292. #endif
  293.             }
  294.             fRefresh = FALSE;
  295.         }
  296. #if defined(THINK_CPLUS) || defined(__MWERKS__)
  297.         fflush(stdout);
  298. #endif
  299.  
  300.         if (fPhase > kMaxPhase)
  301.             setState(kStop);
  302.  
  303.         if (fPhase == kNoPhase &&
  304.             database->isOpen())
  305.             database->commit(TRUE);
  306.     }
  307.  
  308. #ifdef qNeoThreads
  309.     loops = 0;
  310.     while (!fRefresh) {
  311.         CNeoThreadNative::Yield();
  312. #ifdef qNeoDebug
  313.         loops++;
  314.         if (loops > 1000) {
  315.             loops = 0;
  316.             break;
  317.         }
  318. #endif
  319.     }
  320. #endif
  321. }
  322.  
  323. /******************************************************************************
  324.  doSomeWork
  325.  ******************************************************************************/
  326. void CStandApp::doSomeWork(const short aPhase, TMTask *aTimer)
  327. {
  328.     long            done;
  329.     long            IveDone        = 0;
  330.     long            delta;
  331.     long            quantum;
  332.     NeoID            id;
  333.     CNeoPersist *    object;
  334.     CNeoDatabase *    oldDatabase    = gNeoDatabase;
  335.     CNeoDatabase *    database    = getDatabase();
  336.     TMTask            updateTask;
  337.  
  338. #ifdef qNeoThreads
  339.     quantum = 500 / fPhaseInfo[aPhase].threadCount;
  340. #else
  341.     quantum = 500;
  342. #endif
  343.     if (fPhaseInfo[aPhase].delta + fPhaseInfo[aPhase].done < fPhaseInfo[aPhase].target) {
  344.         gNeoDatabase = database;
  345.  
  346.         updateTask.tmAddr = nil;
  347.         updateTask.qType = 0;
  348.         updateTask.tmCount = 0;
  349.         updateTask.tmWakeUp = 0;
  350.         updateTask.tmReserved = 0;
  351.         InsXTime((QElem *)&updateTask);
  352.         PrimeTime((QElem *)&updateTask, quantum);
  353.  
  354.         aTimer->tmAddr = nil;
  355.         aTimer->qType = 0;
  356.         aTimer->tmCount = 0;
  357.         aTimer->tmWakeUp = 0;
  358.         aTimer->tmReserved = 0;
  359.         InsXTime((QElem *)aTimer);
  360.         PrimeTime((QElem *)aTimer, k30MicroMinutes);
  361.     
  362.         while ((updateTask.qType&0x8000) &&
  363.                (fPhaseInfo[aPhase].delta + fPhaseInfo[aPhase].done < fPhaseInfo[aPhase].target)) {
  364.     
  365.             fPhaseInfo[aPhase].done++;
  366.             IveDone++;
  367.  
  368.             switch (aPhase) {
  369.             case    kInsert:
  370.                 /*------------------------------------------------------*/
  371.                 /* Perform the code for record insertion sequence         */
  372.                 /*------------------------------------------------------*/
  373.                 object = new CFiller;
  374.                 FailNIL(object);
  375.                 delta = fPhaseInfo[kInsert].delta;
  376.                 done = fPhaseInfo[kInsert].done;
  377.                 object->fID = delta + done;
  378.                 database->addObject(object);
  379.                 object->unrefer();
  380.                 if (delta + done == fPhaseInfo[kInsert].target) {
  381.                     if (database->isOpen())
  382.                         database->commit(FALSE);
  383.                 }
  384.                 break;
  385.  
  386.             case    kRandomly:
  387.                 /*------------------------------------------------------*/
  388.                 /* Perform the code for randomly searching sequence     */
  389.                 /*------------------------------------------------------*/
  390.                 id = (rand()&0x7FFFFFFF) % fPhaseInfo[kInsert].target;
  391.                 if (!id)
  392.                     id = fPhaseInfo[kInsert].target / 2;
  393.                 object = (CFiller *)CFiller::FindByID(database, kFillerID, id, FALSE);
  394.                 NeoAssert(object);
  395.                 object->unrefer();
  396.                 break;
  397.  
  398.             case    kSerially:
  399.                 /*------------------------------------------------------*/
  400.                 /* Serially iterate over a class of objects                */
  401.                 /*------------------------------------------------------*/
  402.                 if (fIterator) {
  403.                     object = fIterator->nextObject();
  404.                     if (!object) {
  405.                         fIterator->reset();
  406.                         object = fIterator->currentObject();
  407.                     }
  408.                 }
  409.                 else {
  410.                     fIterator = new CNeoIndexIterator(database, kFillerID, nil, FALSE, FALSE);
  411.                     object = fIterator->currentObject();
  412.                 }
  413.                 NeoAssert(object);
  414.                 break;
  415.  
  416.             case    kChange:
  417.                 /*------------------------------------------------------*/
  418.                 /* Perform the code for Change sequence here            */
  419.                 /*------------------------------------------------------*/
  420.                 if (fIterator) {
  421.                     object = fIterator->nextObject();
  422.                     if (!object) {
  423.                         fIterator->reset();
  424.                         object = fIterator->currentObject();
  425.                     }
  426.                 }
  427.                 else {
  428.                     fIterator = new CNeoIndexIterator(database, kFillerID);
  429.                     object = fIterator->currentObject();
  430.                 }
  431.                 NeoAssert(object);
  432.                 object->autoReferTo();
  433.                 object->setDirty();
  434.                 object->autoUnrefer();
  435.                 database->setDirty();
  436.                 break;
  437.  
  438.             case    kDelete:
  439.                 /*------------------------------------------------------*/
  440.                 /* Perform the code for Delete sequencing here            */
  441.                 /*------------------------------------------------------*/
  442.                 if (!fIterator)
  443.                     fIterator = new CNeoIndexIterator(database, kFillerID);
  444.                 object = fIterator->currentObject();
  445.                 NeoAssert(object);
  446.                 object->autoReferTo();
  447.                 fIterator->removeCurrent();
  448.                 object->autoUnrefer();
  449.                 break;
  450.             }
  451.         }
  452.  
  453.         if (database->isOpen() &&
  454.             database->isDirty() &&
  455.             CNeoPersist::FCacheUsed > (CNeoPersist::FCacheSize>>1)) {
  456.             database->commit(FALSE);
  457.             setDirty(FALSE);
  458.         }
  459.  
  460.         RmvTime((QElem *)aTimer);
  461.         RmvTime((QElem *)&updateTask);
  462.  
  463.         if (aTimer->tmCount > 0)
  464.             fPhaseInfo[aPhase].soFar += -(k30MicroMinutes + aTimer->tmCount * 1000) - gLoopOverhead;
  465.         else
  466.             fPhaseInfo[aPhase].soFar += -(k30MicroMinutes - aTimer->tmCount) - gLoopOverhead;
  467.         fPhaseInfo[aPhase].committed += IveDone;
  468.         fPhaseInfo[aPhase].dirty = TRUE;
  469.  
  470.         gNeoDatabase = oldDatabase;
  471.     }
  472.     else {
  473. #ifdef __MWERKS__
  474.         fPhaseInfo[aPhase].finished = TRUE;
  475. #endif
  476.         setPhase(aPhase +1);
  477.         if (fIterator) {
  478.             fIterator->setForward(!fIterator->isForward());
  479.             fIterator->reset();
  480.         }
  481.     }
  482. }
  483.     
  484. void CStandApp::exit(void)
  485. {
  486. }
  487.  
  488. /****************************************************************************
  489.     getTargetTotals - This method gets the target totals from the TextBoxes
  490.     in the main dialog for each of the 5 phases.    If there is any of the
  491.     totals that are out of range,    the text in the TextBoxes will be adjusted
  492.     to be within range.
  493. *****************************************************************************/
  494. void    CStandApp::getTargetTotals(void)
  495. {
  496.     short            index;
  497.     
  498.     for (index = kMinPhase; index <= kMaxPhase; index++)
  499.         fPhaseInfo[index].target = default_vals[index];
  500. }
  501.  
  502. /*********************************************************************
  503.     aValue is microseconds of time.
  504.  
  505. *********************************************************************/
  506. void CStandApp::getTime(long aValue, char *aString)
  507. {
  508.     unsigned long    value    = (unsigned long)aValue;
  509.     unsigned long    thous    = ((value % 1000000) / 100);    // get thousandths of seconds
  510.     unsigned long    secs    = ((value / 0x100000) % 60);    // get seconds
  511.     unsigned long    mins    = (value / (0x100000 * 60));    // get minutes
  512.  
  513.     sprintf(aString, "%2.0lu:%2.2lu.%4.4lu", mins, secs, thous);
  514. }
  515.  
  516. #ifdef qNeoThreads
  517. void CStandApp::killThreads(void)
  518. {
  519.     short    index;
  520.  
  521.     for (index = 0; index < kMaxThreads; index++) {
  522.         if (fThreadInfo[index].state == kAlive) {
  523.             NeoAssert(fThreadInfo[index].thread);
  524.             fThreadInfo[index].state = kDie;
  525.             CNeoThreadNative::Yield(fThreadInfo[index].thread);
  526.             fThreadInfo[index].thread = nil;
  527.         }
  528.     }
  529. }
  530. #endif
  531.  
  532. #ifdef qNeoThreads
  533. CBenchThread::CBenchThread(ThreadInfo *aInfo, const NeoThreadType aType, void **aArg, const Size aStackSize, const NeoThreadOptions aOptions)
  534.     : CNeoThreadNative(aType, aArg, aStackSize, aOptions)
  535. {
  536.     fSetTimer = FALSE;
  537.     fInfo = aInfo;
  538. }
  539.  
  540. long CBenchThread::run(void)
  541. {
  542.     while (fInfo->state == kAlive) {
  543.         ((CStandApp *)gNeoApp)->doSomeWork(fInfo->phase, &fTimer);
  544.     
  545.         yield();
  546.     }
  547.  
  548.     fInfo->thread = nil;
  549.  
  550.     return fResult;
  551. }
  552.  
  553. // ---------------------------------------------------------------------------
  554. //        • handleSwapIn
  555. // ---------------------------------------------------------------------------
  556. //    Callback to the Thread Manager.
  557. //    
  558. void CBenchThread::handleSwapIn(void)
  559. {
  560.     inherited::handleSwapIn();
  561.  
  562.     // turn timers back on
  563.     if (fSetTimer) {
  564.         InsXTime((QElem *)&fTimer);
  565.         PrimeTime((QElem *)&fTimer, 0);
  566.     }
  567. }
  568.  
  569. // ---------------------------------------------------------------------------
  570. //        • handleSwapOut
  571. // ---------------------------------------------------------------------------
  572. //    Callback to the Thread Manager.
  573. //    
  574. void CBenchThread::handleSwapOut(void)
  575. {
  576.     // turn timers off
  577.     fSetTimer = fTimer.qType&0x8000;
  578.     if (fSetTimer) {
  579.         RmvTime((QElem *)&fTimer);
  580.         fTimer.tmCount += gLoopOverhead;
  581.     }
  582.  
  583.     inherited::handleSwapOut();
  584. }
  585.  
  586. #endif
  587.  
  588.